import random
import traceback
import time
import threading
import requests
import selenium
from PIL import Image
from selenium import webdriver
from msedge.selenium_tools import Edge, EdgeOptions
from googlenet.identify_verification_code import identify
from load import config
import os

string = config['string']
emails = config['emails']
password = config['password']
code_img_path = config['code_img_path']
urls = config['urls']
proxy_source_url = config['proxy_source_url']
drive_path = config['drive_path']
thread_num = config['thread_num']
xpaths = config['xpaths']


def get_proxy():
    return requests.get(proxy_source_url + '/all').json()


def get_https_proxy():
    print('获取代理IP中')
    ps = get_proxy()
    https_proxy = []
    for p in ps:
        https = p['https']
        if https is not None and https is True:
            https_proxy.append({'http': 'http://' + p['proxy'],
                                'https': 'https://' + p['proxy'],
                                'ip': p['proxy']
                                })
    print('获取代理IP完毕，共{:}个IP'.format(len(https_proxy)))
    return https_proxy


_cur_browser = None


def getBrowser(proxy=None):
    global _cur_browser
    if _cur_browser is not None:
        return _cur_browser
    base_config = config['base_config']

    if base_config["chrome"]:
        options = webdriver.chrome.options.Options()
    else:
        options = EdgeOptions()
    options.use_chromium = True

    if proxy is not None:
        options.add_argument('proxy-server={:}'.format(proxy['ip']))

    if base_config['headless']:
        options.add_argument('--headless')
        options.add_argument('--no-sandbox')
        options.add_argument('--disable-dev-shm-usage')
        options.add_argument('--window-size=%sx%s' % (1920, 1080))

    options.page_load_strategy = 'eager'

    if base_config["chrome"]:
        browser = webdriver.Chrome(options=options, executable_path=base_config['drive_path'])
    else:
        browser = Edge(executable_path=base_config['drive_path'], options=options)
    browser.maximize_window()
    browser.implicitly_wait(3)

    _cur_browser = browser
    return browser


def removeBrowserCache():
    global _cur_browser
    if _cur_browser is not None:
        _cur_browser.delete_all_cookies()


def closeBrowser(closeAll: bool = False):
    global _cur_browser
    if _cur_browser is not None:
        _cur_browser.quit()
        _cur_browser = None
    if closeAll:
        os.system('taskkill /f /im chrome.exe')
        os.system('taskkill /f /im chromedriver.exe')
        _cur_browser = None


def login(uName, password, proxy=None, print=print, id=''):
    browser = getBrowser(proxy)
    logout_url = urls['logout_url']
    login_url = urls['login_url']
    index_url = urls['index_url']
    try:
        # browser.set_window_size(1200, 800)
        # browser.get(logout_url)
        browser.get(login_url)

        maxTryN = 5
        curN = 0
        while curN < maxTryN:
            time.sleep(3)
            try:

                name_input = browser.find_element_by_xpath(xpaths['登录_用户名输入框'])
                password_input = browser.find_element_by_xpath(xpaths['登录_密码输入框'])

                code_input = browser.find_element_by_xpath(xpaths['登录_验证码输入框'])

                code_img = browser.find_element_by_xpath(xpaths['登录_验证码图片'])
                register_btn = browser.find_element_by_xpath(xpaths['登录_按钮'])
            except selenium.common.exceptions.NoSuchElementException as ex:
                print('通过xpath定位时，{:}元素未找到'.format(xpaths.current_key))
                closeBrowser()
                return -1

            # name = ''.join([random.choice(string) for i in range(8)])
            name = uName

            name_input.send_keys(name)
            password_input.send_keys(password)
            code_img.screenshot(code_img_path + 'code{:}.png'.format(id))
            code = identify(code_img_path + 'code{:}.png'.format(id))
            print(code)

            code_input.clear()
            code_input.send_keys(code)
            register_btn.click()
            time.sleep(1)
            try:
                login_info = browser.find_element_by_xpath(xpaths['登录_提示信息'])
                if login_info.is_displayed():
                    break
            except:
                pass
            curN += 1
            browser.get(login_url)

            print(f"输入验证码错误，第{curN}次重试")
        browser.get(index_url)
        print('登录完成')
        try:
            qiandao = browser.find_element_by_xpath(xpaths['登录_签到'])
            qiandao.click()
            print('签到成功')
        except selenium.common.exceptions.NoSuchElementException as ex:
            try:
                yiQianDao = browser.find_element_by_xpath(xpaths['登录_已签到'])
                print("已签到，无需再签到")
            except selenium.common.exceptions.NoSuchElementException as ex:
                print("未找到签到按钮，也未找到已签到按钮")
                closeBrowser()
                return -1
    except:
        print(traceback.format_exc())
        return -1
    finally:
        removeBrowserCache()
    return 0


def register(uName, proxy=None, print=print, id=''):
    register_url = urls['register_url']
    logout_url = urls['logout_url']

    browser = getBrowser(proxy)
    try:
        # browser.set_window_size(1200, 800)
        browser.get(logout_url)
        browser.get(register_url)
        try:
            go_register = browser.find_element_by_xpath(xpaths['跳转注册'])
            browser.get(go_register.get_attribute('href'))
            agree_btn = browser.find_element_by_xpath(xpaths['同意按钮'])
            agree_btn.click()
            name_input = browser.find_element_by_xpath(xpaths['用户名输入框'])
            password_input = browser.find_element_by_xpath(xpaths['密码输入框'])
            re_password_input = browser.find_element_by_xpath(xpaths['确认密码输入框'])
            email_input = browser.find_element_by_xpath(xpaths['邮箱输入框'])
            time.sleep(1)
            code_input = browser.find_element_by_xpath(xpaths['验证码输入框'])
            code_img = browser.find_element_by_xpath(xpaths['验证码图片'])
            register_btn = browser.find_element_by_xpath(xpaths['注册按钮'])
        except selenium.common.exceptions.NoSuchElementException as ex:
            print('通过xpath定位时，{:}元素未找到'.format(xpaths.current_key))
            closeBrowser()
            return -1

        # name = ''.join([random.choice(string) for i in range(8)])
        name = uName
        email = ''.join([random.choice(string) for i in range(5)]) + random.choice(emails)
        name_input.send_keys(name)
        password_input.send_keys(password)
        re_password_input.send_keys(password)
        email_input.send_keys(email)

        # browser.get_screenshot_as_file(code_img_path + 's.png')
        # left = int(code_img.location['x'])
        # top = int(code_img.location['y'])
        # right = int(code_img.location['x'] + code_img.size['width'])
        # bottom = int(code_img.location['y'] + code_img.size['height'])

        # # 通过Image处理图像
        # im = Image.open(code_img_path + 's.png')
        # im = im.crop((left, top, right, bottom))
        # im.save(code_img_path + 'code.png')

        code_img.screenshot(code_img_path + 'code{:}.png'.format(id))

        code = identify(code_img_path + 'code{:}.png'.format(id))
        print(code)
        code_input.send_keys(code)
        register_btn.click()
        register_info = None
        for i in range(3):
            try:
                register_info = browser.find_element_by_xpath(xpaths['注册提示信息'])
                if register_info.is_displayed():
                    break
            except selenium.common.exceptions.NoSuchElementException as ex:
                register_info = None
            time.sleep(0.5)
        if register_info is None:
            print('通过xpath定位时，{:}元素未找到'.format(xpaths.current_key))
            return -1
        print('注册完成')

    except:
        print(traceback.format_exc())
        return -1
    finally:
        removeBrowserCache()
    return 0


def proxy_test(proxys, test_url):
    rp = []
    print('代理IP测试中')
    for proxy in proxys:
        try:
            print('测试：{:}'.format(proxy))
            requests.get(test_url, proxies=proxy, timeout=5)
            rp.append(proxy)
            print('测试通过')
        except requests.exceptions.ConnectTimeout or requests.exceptions.ReadTimeout:
            print('连接超时，测试不通过')
            # a = requests.get(proxy_source_url+'/delete?proxy=host:{:}'.format(proxy['ip']))
        except requests.exceptions.ProxyError:
            print('代理错误，测试不通过')
        except Exception as ex:
            traceback.print_exc()
            print('测试不通过')

    print('经过测试，有{:}个IP可用'.format(len(rp)))
    return rp


class ProxyThread(threading.Thread):
    thread_pool = []
    lock = threading.Lock()

    def __init__(self, id, proxy):
        threading.Thread.__init__(self)
        self.s = []
        self.id = id
        self.proxy = proxy

    @classmethod
    def is_pool_null(cls):
        return len(cls.thread_pool) == 0

    @classmethod
    def join(cls):
        while len(cls.thread_pool) > 0:
            time.sleep(0.1)

    @classmethod
    def __add_thread__(cls, td):
        cls.lock.acquire()
        cls.thread_pool.append(td)
        cls.lock.release()

    @classmethod
    def __remove_thread__(cls, td):
        cls.lock.acquire()
        try:
            cls.thread_pool.remove(td)
        except:
            pass
        cls.lock.release()

    def run(self):
        print('thread_{:}：启动'.format(self.id))
        ProxyThread.__add_thread__(self)
        try:
            register(object_url, drive_path, self.proxy, print=self.xprint, id=self.id)
        except Exception as ex:
            print('thread_{:}出现异常：{:}'.format(self.id, str(ex)))
        for s in self.s:
            print('thread_{:}：{:}'.format(self.id, s))
        ProxyThread.__remove_thread__(self)
        print('thread_{:}：结束'.format(self.id))

    def xprint(self, s):
        self.s.append(s)


def randSort(listValue: list):
    for i in range(len(listValue)):
        randIndex = random.Random().randint(0, len(listValue)-1)
        tmp = listValue[i]
        listValue[i] = listValue[randIndex]
        listValue[randIndex] = tmp


def registerUserList(userNameList: list[str], randChoose: bool = False) -> list[str]:
    try:
        return __registerUserList(userNameList=userNameList, randChoose=randChoose)
    except:
        print(traceback.format_exc())
    finally:
        closeBrowser(closeAll=True)


def __registerUserList(userNameList: list[str], randChoose: bool = False) -> list[str]:
    failNameList = []
    if randChoose:
        randSort(userNameList)
    for i, user in enumerate(userNameList):
        print(f"第{i}个账号：{user}准备注册")
        rs = register(uName=user, proxy=None, print=print)
        if rs == 0:
            print(f"第{i}个账号：注册：{user}成功")
        else:
            failNameList.append(user)
            print(f"第{i}个账号：注册：{user}失败")
    print(f"总共{len(userNameList)}个用户，成功注册{len(userNameList) - len(failNameList)}个，失败{len(failNameList)}个")
    return failNameList


def loginAndQianDaoUsers(userNameList: list[str],  randChoose: bool = False) -> list[str]:
    try:
        return __loginAndQianDaoUsers(userNameList=userNameList, randChoose=randChoose)
    except:
        print(traceback.format_exc())
    finally:
        closeBrowser(closeAll=True)


def __loginAndQianDaoUsers(userNameList: list[str], randChoose: bool = False) -> list[str]:
    failNameList = []
    if randChoose:
        randSort(userNameList)

    for i, user in enumerate(userNameList):
        print(f"第{i}个账号：{user}准备登录签到")
        rs = login(user, password=config['password'], proxy=None)
        if rs == 0:
            print(f"第{i}个账号：{user}登录签到成功")
        else:
            failNameList.append(user)
            print(f"第{i}个账号：{user}登录签到失败")
    print(f"总共{len(userNameList)}个用户，成功签到{len(userNameList)-len(failNameList)}个，失败{len(failNameList)}个")
    return failNameList


